package com.googlecode.gamedroid.gamepad;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;

import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.support.v4.app.NavUtils;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.WindowManager.LayoutParams;
import android.widget.RelativeLayout;
import android.widget.Toast;

import com.googlecode.gamedroid.Connection;
import com.googlecode.gamedroid.Preferences;
import com.googlecode.gamedroid.R;
import com.googlecode.gamedroid.event.source.EventSource;
import com.googlecode.gamedroid.sockethelper.DeviceList;
import com.googlecode.gamedroid.sockethelper.ISocket;

public abstract class GamePad extends Activity
{
	public static int getDescription(Class<? extends GamePad> gamepad)
	{
		Method method = null;
		try
		{
			method = gamepad.getDeclaredMethod("getDescription");
		}
		catch(NoSuchMethodException e)
		{
			e.printStackTrace();
		}
		try
		{
			return (Integer) method.invoke(null);
		}
		catch(IllegalArgumentException e)
		{
			e.printStackTrace();
		}
		catch(IllegalAccessException e)
		{
			e.printStackTrace();
		}
		catch(InvocationTargetException e)
		{
			e.printStackTrace();
		}
		return 0;
	}
	
	public static int getIcon(Class<? extends GamePad> gamepad)
	{
		Method method = null;
		try
		{
			method = gamepad.getDeclaredMethod("getIcon");
		}
		catch(NoSuchMethodException e)
		{
			e.printStackTrace();
		}
		try
		{
			return (Integer) method.invoke(null);
		}
		catch(IllegalArgumentException e)
		{
			e.printStackTrace();
		}
		catch(IllegalAccessException e)
		{
			e.printStackTrace();
		}
		catch(InvocationTargetException e)
		{
			e.printStackTrace();
		}
		return R.drawable.ic_launcher;
	}
	
	public static int getLabel(Class<? extends GamePad> gamepad)
	{
		Method method = null;
		try
		{
			method = gamepad.getDeclaredMethod("getLabel");
		}
		catch(NoSuchMethodException e)
		{
			e.printStackTrace();
		}
		try
		{
			return (Integer) method.invoke(null);
		}
		catch(IllegalArgumentException e)
		{
			e.printStackTrace();
		}
		catch(IllegalAccessException e)
		{
			e.printStackTrace();
		}
		catch(InvocationTargetException e)
		{
			e.printStackTrace();
		}
		return 0;
	}
	
	private AlertDialog dialogLoading;
	private boolean fullscreen;
	private SharedPreferences mPreferences;
	private LinkedList<EventSource> sources = new LinkedList<EventSource>();
	private Vibrator vibrator;
	private View viewRoot;
	public Connection connection = new Connection();
	
	protected void addSource(EventSource object)
	{
		sources.add(object);
	}
	
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		
		requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
		
		getActionBar().setDisplayHomeAsUpEnabled(true);
		
		getWindow().setFlags(LayoutParams.FLAG_KEEP_SCREEN_ON, LayoutParams.FLAG_KEEP_SCREEN_ON);
		
		if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) // can't use dynamic fullscreen
			getWindow().setFlags(LayoutParams.FLAG_FULLSCREEN, LayoutParams.FLAG_FULLSCREEN);
		
		PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
		mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
		
		setUpViews();
		
		vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
		
		viewRoot = findViewById(R.id.root);
		View marginRight = findViewById(R.id.margin_right);
		
		if(marginRight != null)
		{
			String margin = mPreferences.getString(
				Preferences.PREF_RIGHT_MARGIN,
				getResources().getString(R.string.pref_right_margin_default));
			
			RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) marginRight.getLayoutParams();
			lp.setMargins(0, 0, Integer.parseInt(margin), 0);
			marginRight.setLayoutParams(lp);
		}
		
		setUpSources();
		
		dialogLoading =
				new AlertDialog.Builder(this)
					.setTitle(R.string.title_loading)
					.setCancelable(false)
					.setView(getLayoutInflater().inflate(R.layout.dialog_progressbar, null))
					.create();
		
		startConnection();
	}
	
	@Override
	protected void onDestroy()
	{
		dialogLoading.cancel();
		super.onDestroy();
		try
		{
			connection.stop();
		}
		catch(Connection.StatusException e)
		{}
	}
	
	@Override
	protected void onStart()
	{
		super.onStart();
		
		if(mPreferences.getBoolean(Preferences.PREF_ROTATE180, false))
			setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
		else
			setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
	}
	
	protected abstract void setUpSources();
	
	protected abstract void setUpViews();
	
	protected void startConnection()
	{
		dialogLoading.show();
		
		ISocket socket = DeviceList.getSocket(getIntent());
		
		try
		{
			connection.start(this, socket);
		}
		catch(Connection.StatusException e)
		{}
	}
	
	@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
	protected void toggleFullscreen(boolean active)
	{
		if(active)
		{
			getActionBar().hide();
			
			if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
				viewRoot.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN);
			else
				viewRoot.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
		}
		else
		{
			getActionBar().show();
			
			if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
				viewRoot.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
			else
				viewRoot.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
		}
		fullscreen = active;
	}
	
	public void feedback()
	{
		if(mPreferences.getBoolean(Preferences.PREF_VIBRATION, true))
		{
			String duration = mPreferences.getString(
				Preferences.PREF_VIBRATION_DURATION,
				getResources().getString(R.string.pref_vibration_duration_default));
			vibrator.vibrate(Integer.parseInt(duration));
		}
	}
	
	public void onBtnDisconnectClick(MenuItem item)
	{
		try
		{
			connection.stop();
		}
		catch(Connection.StatusException e)
		{}
	}
	
	public void onBtnFullscreenClick(View v)
	{
		toggleFullscreen(!fullscreen);
	}
	
	public void onBtnResetClick(MenuItem item)
	{
		connection.reset();
	}
	
	public void onBtnVibrationClick(MenuItem item)
	{
		boolean newValue = !mPreferences.getBoolean(Preferences.PREF_VIBRATION, true);
		mPreferences
			.edit()
			.putBoolean(Preferences.PREF_VIBRATION, newValue)
			.commit();
		item.setChecked(newValue);
	}
	
	public void onConnectionCreated()
	{
		try
		{
			for(EventSource source : sources)
			{
				connection.addEventSource(source);
			}
			connection.forward();
		}
		catch(Connection.StatusException e)
		{}
		
		dialogLoading.hide();
		
		Handler h = new Handler();
		h.postDelayed(new Runnable()
		{
			@Override
			public void run()
			{
				toggleFullscreen(true);
			}
		}, 500);
		Toast.makeText(this, R.string.msg_fullscreen, Toast.LENGTH_SHORT).show();
	}
	
	public void onConnectionLost()
	{
		Toast.makeText(this, R.string.msg_connection_closed, Toast.LENGTH_SHORT).show();
		dialogLoading.hide();
		finish();
	}
	
	public void onConnectionReceive(String data)
	{}
	
	public boolean onCreateOptionsMenu(Menu menu)
	{
		// TODO change icon
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.activity_gamepad, menu);
		return true;
	}
	
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event)
	{
		if(keyCode == KeyEvent.KEYCODE_BACK)
		{
			return true;
		}
		return super.onKeyDown(keyCode, event);
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item)
	{
		switch(item.getItemId())
		{
			case android.R.id.home:
				NavUtils.navigateUpFromSameTask(this);
				try
				{
					connection.stop();
				}
				catch(Connection.StatusException e)
				{}
				return true;
				
			default:
				return super.onOptionsItemSelected(item);
		}
	}
}
